import { Postcard } from './postcard';
import { HRouter } from "./hrouter";
import { GlobalContext } from './GlobalContext';

export interface IInterceptor {
  process: (postcard: Postcard, callback: InterceptorCallback) => void;
}

export interface InterceptorCallback {
  onContinue: (postcard: Postcard) => void;
  onInterrupt: (postcard: Postcard) => void;
}


export function navigationWithInterceptor(postcard: Postcard) {
  if (postcard.getGreenChannel()) {
    HRouter.getInstance()._navigation(postcard)
  } else {
    let interceptor: Interceptor = GlobalContext.getContext().getObject("interceptor") as Interceptor
    if (interceptor != null) {
      interceptor.process(postcard)
    } else {
      HRouter.getInstance()._navigation(postcard)
    }
  }
}

export function registerInterceptor(iInterceptor: IInterceptor) {
  let interceptor: Interceptor = GlobalContext.getContext().getObject("interceptor") as Interceptor
  if (interceptor == null) {
    GlobalContext.getContext().setObject("interceptor", new Interceptor(iInterceptor));
  } else {
    interceptor.registerIIterceptor(iInterceptor);
  }
}

export function unregisterInterceptor() {
  GlobalContext.getContext().setObject("interceptor", null);
}

class Interceptor implements IInterceptor {
  private callback: InterceptorCallback
  private interceptors: Array<IInterceptor> = []

  constructor(iInterceptor: IInterceptor) {
    this.interceptors.push(iInterceptor);
    this.callback = {
      onInterrupt(postcard: Postcard) {
        if (postcard != null && postcard.getNavigationCallback() != null) {
          postcard.getNavigationCallback()!.onInterrupt(postcard)
        }
      },
      onContinue(postcard: Postcard) {
        HRouter.getInstance()._navigation(postcard)
      }
    };
    GlobalContext.getContext().setObject("interceptor", this);
  }

  async process(postcard: Postcard) {
    for (let i = 0; i < this.interceptors.length; i++) {
      let result = await this.onProcess(this.interceptors[i], postcard)
      if (!result.continue) {
        this.callback.onInterrupt(result.postcard)
        return
      }
      postcard = result.postcard
    }
    this.callback.onContinue(postcard)
  }

  private onProcess(iInterceptor: IInterceptor, postcard: Postcard): Promise<InterceptorResult> {
    return new Promise((resolve, _) => {
      let nextCallBack = {
        onInterrupt(postcard: Postcard) {
          resolve({postcard:postcard,continue:false})
        },
        onContinue(postcard: Postcard) {
          resolve({postcard:postcard,continue:true})
        }
      }
      iInterceptor.process(postcard, nextCallBack)
    })
  }

  registerIIterceptor(iInterceptor: IInterceptor) {
    this.interceptors.push(iInterceptor)
  }
}

interface InterceptorResult{
  postcard:Postcard
  continue:boolean
}